package DataServer

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
	"text/template"

	"gitee.com/dark.H/DataDash/in"
	"github.com/gorilla/websocket"
)

func SearchHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		op := r.PostFormValue("op")
		key := strings.TrimSpace(r.PostFormValue("data"))
		// console.log()
		in.ColorL("Search Handler:", op, key)
		if op == "search" {
			var datas in.Datas
			if key == "" {
				// var datas in.Datas
				in.ColorL("Get Dataset")
				for name := range in.DataSets {
					id := in.MemoryGetCacheId(name)
					if tps := strings.Split(name, "/"); len(tps) > 1 {
						la := tps[len(tps)-1]
						pre := tps[:len(tps)-1]
						d := in.G{
							"id":    id,
							"label": strings.Join(pre, "/"),
							"title": la,
						}
						datas = append(datas, d)
					}

				}

			} else if strings.Contains(key, ":") || strings.Contains(key, "=") {

				filter := in.LineToDict(key)
				in.ColorD(filter)
				datas = in.MemoryDictSearch(filter)
			} else {
				datas = in.MemoryKeySearch(key)
			}
			log.Println("Found: ", len(datas))
			SearchedDatasAddNodeView(datas, true)

			if msg, err := json.Marshal(&Msg{
				Op:   "search",
				Data: datas,
			}); err != nil {
				in.FlowFromList(fmt.Sprint(err)).Action()
				log.Println("search Key error:", err)
				w.Write([]byte("{}"))
			} else {
				w.Write(msg)
			}

		} else if op == "attr" {

			attrs := in.MemoryKeys()
			if msg, err := json.Marshal(&struct {
				Op   string
				Data []string
			}{
				Op:   "attrs",
				Data: attrs,
			}); err != nil {
				in.FlowFromList(fmt.Sprint(err)).Action()
				log.Println("search Key error:", err)
				w.Write([]byte("{}"))
			} else {
				w.Write(msg)
			}

		}
	}

}

func WsAPI(w http.ResponseWriter, r *http.Request) {
	c, err := Upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Print("upgrade:", err)
		return
	}
	defer c.Close()
	backWaitC := false
	for {
		mt, message, err := c.ReadMessage()
		if !backWaitC {
			go queueToReply(c, mt)
			backWaitC = true
		}
		if err != nil {
			log.Println("read:", err)
			break
		}

		HandleWs(c, mt, message)

		if err != nil {
			log.Println("write:", err)
			break
		}
	}
}

func HandleWs(c *websocket.Conn, mt int, message []byte) {
	log.Printf("recv: %s", message)
	data := make(in.G)
	json.Unmarshal([]byte(message), &data)
	in.ColorD(data)
	op := data["op"].(string)
	defer func() {
		DisplaySettings.LastOper = op
	}()
	if op == "new" {
		//
		//  NEW AREA
		go in.SearchByUI(func(bottle in.BottleInterface, oper *in.Oper) {

			datas := bottle.Query(oper)

			id := in.MemoryGetCacheId(bottle.GetName() + "/" + oper.Name)
			in.ColorL("Query:", len(datas), id, bottle.GetName()+"/"+oper.Name)
			c.WriteMessage(mt, in.ToJson(in.G{
				"op": "new",
				"data": []in.G{
					{
						"id":    id,
						"label": bottle.GetName(),
						"title": oper.Name,
					},
				},
			}))
		}, func(err error) {
			c.WriteMessage(mt, in.ToJson(in.G{
				"op":   "err",
				"data": []string{fmt.Sprint(err)},
			}))

		})
	} else if op == "detail" {

		datad := data["data"].(map[string]interface{})
		label := datad["label"].(string)
		operName := datad["title"].(string)
		// log.Println(label+"/"+operName, "|", in.MemoryKeys())
		memdatas := in.MemoryGet(strings.TrimSpace(label + "/" + operName))
		SearchedDatasAddNodeView(memdatas, false)
		OperReply(c, mt, "detail", memdatas)
	} else if op == "matchWith" {
		allkeys := in.MemoryKeys()
		if use, whichKey, _ := in.FlowFromList(allkeys...).Action(); use {
			go NodeConnectWith(c, mt, strings.TrimSpace(whichKey))
		}
	} else if op == "groupBy" {
		allkeys := in.MemoryKeys()
		if use, whichKey, _ := in.FlowFromList(allkeys...).Action(); use {
			go NodeGroupBy(c, mt, strings.TrimSpace(whichKey))
		}
	} else if op == "similary" {
		nodeid := int32(data["data"].(float64))
		allkeys := in.MemoryKeys()
		if use, whichKey, _ := in.FlowFromList(allkeys...).Action(); use {
			go NodeSimilary(c, mt, nodeid, whichKey)
		}
	} else if op == "Tree" {
		allkeys := in.MemoryKeys()
		if len(allkeys) > 1 {
			if use, frKey, _ := in.FlowFromList(allkeys...).Action(); use {
				if use, toKey, _ := in.FlowFromList(allkeys...).Action(); use {
					go NodeHierarchy(c, mt, frKey, toKey)
				}
			}
		} else {
			c.WriteMessage(mt, in.ToJson(in.G{
				"op":   "err",
				"data": []string{"No enough keys to match!!!"},
			}))
		}

	} else if op == "clear" {
		NowPanelNodes = make(in.NodeView)
		NowPanelEdge = make(in.Edges)
	} else if op == "clearEdge" {
		NowPanelEdge = make(in.Edges)
	} else if op == "clearNode" {
		NowPanelNodes = make(in.NodeView)
	} else if op == "pageNext" {
		go func() {
			DisplaySettings.Page++
			datas := in.MemoryGet(in.MemLastInfo.LastConnectStr + "/" + in.MemLastInfo.LastTbStr)
			OperReply(c, mt, "detail", datas)
		}()
	} else if op == "dataPageNext" {
		go in.MemoryNextPage(func(bottle in.BottleInterface, datas in.Datas, err error) {
			if err != nil {
				panic(err)
			}
			memdatas := in.MemoryGet(bottle.GetName() + "/" + in.MemLastInfo.LastTbStr)
			in.ColorL("Next", in.MemLastInfo.MemPage, len(memdatas))
			SearchedDatasAddNodeView(memdatas, false)
			OperReply(c, mt, "detail", memdatas)
		})

	} else if op == "pageLen" {
		if use, pageLen, _ := in.FlowFromList("> 每一页查询的数目 :1000").Action(); use {
			if pl, err := strconv.Atoi(pageLen); err == nil {
				in.MemorySetPageLen(pl)
				c.WriteMessage(mt, in.ToJson(in.G{
					"op":   "err",
					"data": []string{"设置完成"},
				}))
				return
			}

		}
		c.WriteMessage(mt, in.ToJson(in.G{
			"op":   "err",
			"data": []string{"设置失败"},
		}))

	}

}

func GetMenuHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		op := r.PostFormValue("op")
		// key := r.PostFormValue("data")
		in.ColorL(op)
		if op == "dataset /" {
			names := []string{}
			for name := range in.DataSets {
				names = append(names, name)
			}
			if msg, err := json.Marshal(names); err == nil {
				w.Write(msg)
			} else {
				w.Write([]byte{})
				log.Println("Err in Menu get action:", err)
			}
		} else {

		}
	}
}

func FileHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		r.ParseMultipartForm(1024 << 20)
		// f := r.Form.Get("passFile")
		// fmt.Println(f)
		file, handler, err := r.FormFile("passFile")
		if err != nil {
			fmt.Println(err)
			return
		}
		fmt.Println(file, handler.Header)

		if tmpFile, err2 := os.Create("/tmp/" + handler.Filename); err2 == nil {
			if _, err = io.Copy(tmpFile, file); err != nil {
				log.Println("copy", err)
			}
			tmpFile.Close()

			in.SearchFileByUI("/tmp/"+handler.Filename, func(bottle in.BottleInterface, oper *in.Oper) {
				oper.Page = MemPage
				oper.Len = MemPageLen
				bottle.Query(oper)
				id := in.MemoryGetCacheId(bottle.GetName() + "/" + oper.Name)
				msg := Msg{
					Op: "new",
					Data: []in.G{
						{
							"id":    id,
							"label": bottle.GetName(),
							"title": oper.Name,
						},
					},
				}
				if buf2, err := json.Marshal(msg); err == nil {
					log.Println(string(buf2))
					w.Write(buf2)
				}
			}, func(err error) {
				log.Println("File drag Error:", err)
			})
		}
		// }
		defer file.Close()
		// fmt.Fprintf(w, "%v", handler.Header)

	}
}

func HandleErr(c *websocket.Conn, mt int, err error) {
	messageByte, _ := json.Marshal(&in.G{
		"op": "err",
		"data": []string{
			fmt.Sprint(err),
		},
	})
	c.WriteMessage(mt, messageByte)
}

func IndexHandler(w http.ResponseWriter, r *http.Request) {
	// title := r.URL.Path[len("/index"):]
	// p, _ :=loadPage(title)
	t, _ := template.ParseFiles("App/index.html")
	t.Execute(w, nil)
}

func GraphDataOperHandler(w http.ResponseWriter, r *http.Request) {
	var mkey string
	if r.Method == "POST" {
		op := r.PostFormValue("op")
		key := r.PostFormValue("data")

		if strings.HasPrefix(in.MemLastInfo.LastConnectStr, "/") {
			mkey = in.MemLastInfo.LastConnectStr
		} else {
			mkey = in.MemLastInfo.LastConnectStr + "/" + in.MemLastInfo.LastTbStr
		}
		// in.ColorL(op, in.MemLastInfo, "|", in.MemLastInfo.LastConnectStr+"/"+in.MemLastInfo.LastTbStr)
		if op == "graph" {
			if gql, err := in.CompileGQL(key); err != nil {
				w.Write([]byte(err.Error()))
				log.Println("Err in Menu get action:", err)
			} else {
				var datas in.Datas
				in.ColorL("dataset:", gql.Dataset, "layout:", gql.Layout, "gql filter:", gql.FilterKey)
				in.ColorD(gql.QUERY)
				in.ColorD(gql.RENDERKEY)
				if gql.Dataset != "" && len(gql.Dataset) > 3 {
					// name := ""

					for name := range in.DataSets {
						if strings.Contains(name, gql.Dataset) {
							id := in.MemoryGetCacheId(name)
							if id == -1 {
								continue
							}
							t := in.MemoryGet(name)
							datas = append(datas, t...)

						}
					}
					// datas := in.MemoryGet(in.Memory)
				} else {
					datas = in.MemoryAll()
				}

				in.ColorL("len:", len(datas), mkey)

				out := datas.OperWith(gql)
				in.ColorL("b out:", len(out))
				outTree, err := out.TryToGetTree()
				if err != nil {
					log.Fatal(err)
				}
				for _, edge := range out {
					tid := edge["from"].(int)
					sub := outTree.Nodes[tid].SubNodeCount
					edge["width"] = sub * 2
					edge["fromP"].(in.G)["data"].(in.G)["Sub Node Count"] = sub
				}
				// in.ColorL("a out:", len(out))

				var outToRender in.G
				if gql.Layout == "veritcal" {
					outToRender = in.G{
						"op":     "graph",
						"data":   out,
						"layout": "veritcal",
					}
				} else {
					outToRender = in.G{
						"op":   "graph",
						"data": out,
					}
				}
				if msg, err := json.Marshal(outToRender); err == nil {
					w.Write(msg)
				} else {
				}
			}

		} else {

		}
	}
}
